package com.demoworld.com.whitetiger;

import jdk.net.SocketFlow;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.transport.client.PreBuiltTransportClient;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * Created by francislee on 24/07/2017.
 * 简单的对es操作的封装
 * ps：
 * 1。 多个连续的操作， 请使用相同的client， 多次操作完毕后调用close方法
 * 2。 对es操作后， 需要调用close方法
 */
public class ElasticSearchClient {
    private String clusterName;
    private Map<String, Integer> mapTransports;
    private TransportClient client;

    /**
     * init an instance
     * @param clusterName 集群名字
     * @param mapTransports key=es host， value=es port
     */
    public ElasticSearchClient(String clusterName, Map<String, Integer> mapTransports){
        this.clusterName = clusterName;
        this.mapTransports = mapTransports;
        this.init();
    }

    private void init(){
        Settings esSettings = Settings.builder()
                .put("cluster.name", this.clusterName) //设置ES实例的名称
                .put("client.transport.sniff", true) //自动嗅探整个集群的状态，把集群中其他ES节点的ip添加到本地的客户端列表中
                .build();
        client = new PreBuiltTransportClient(esSettings);//初始化client较老版本发生了变化，此方法有几个重载方法，初始化插件等。
        if(this.mapTransports==null || this.mapTransports.isEmpty()){
            return;
        }
        //此步骤添加IP，至少一个，其实一个就够了，因为添加了自动嗅探配置
        try {
            for(Map.Entry<String, Integer> item: this.mapTransports.entrySet()){
                client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(item.getKey()), item.getValue()));
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取全部节点信息
     * @return
     */
    public List<DiscoveryNode> getAllNodes() {
        List<DiscoveryNode> nodes = client.connectedNodes();
        return nodes;
    }

    /**
     * 添加一个文档到指定的索引中
     * @param indexName 索引名字
     * @param typeName 索引类型名字
     * @param id 待添加的文档id
     * @param doc 文档本身内容
     * @return 执行状态
     */
    public ESResult add(String indexName, String typeName, String id,Map<String, Object> doc){
        ESResult tmpResult=new ESResult();
        IndexResponse indexResponse = client.prepareIndex(indexName, typeName, id).setSource(doc).execute().actionGet();
        if(indexResponse==null || indexResponse.status()==null){
            tmpResult.setReturnCode(Statuses.unknownResponse);
            return tmpResult;
        }
        tmpResult.setReturnCode(Statuses.success);
        return tmpResult;
    }

    /**
     * 通过id查询一个文档信息
     * @param indexName 索引名字
     * @param typeName 类型名字
     * @param id id
     * @return ESResult
     */
    public ESResult getById(String indexName, String typeName, String id) {
        ESResult tmpResult=new ESResult();
        GetResponse response = client.prepareGet(indexName, typeName, id).execute().actionGet();
        if(response==null){
            tmpResult.setReturnCode(Statuses.unknownResponse);
            return tmpResult;
        }
        tmpResult.setReturnString(response.getSourceAsString());
        return tmpResult;
    }

    /**
     * 更新一个文档
     * 对没有的字段添加, 对已有的字段替换
     * @param indexName 索引名字
     * @param typeName 类型名字
     * @param id 文档id
     * @param newDoc 新文档内容
     * @return ESResult
     */
    public ESResult updateById(String indexName, String typeName, String id, Map<String, Object> newDoc) {
        ESResult tmpResult=new ESResult();
        UpdateRequest updateRequest = new UpdateRequest();
        updateRequest.index(indexName);
        updateRequest.type(typeName);
        updateRequest.id(id);
        try {
            updateRequest.doc(XContentFactory.jsonBuilder()
                    .startObject()
                    .map(newDoc)//
                    .endObject());
        } catch (IOException e) {
            tmpResult.setReturnCode(Statuses.unknownResponse);
            tmpResult.setReturnString(e.getMessage());
            e.printStackTrace();
        }
        if(tmpResult.isSuccess()){
            return tmpResult;
        }
        UpdateResponse response = null;
        try {
            response = client.update(updateRequest).get();
        } catch (InterruptedException e) {
            tmpResult.setReturnCode(Statuses.esException);
            tmpResult.setReturnString(e.toString());
            e.printStackTrace();
        } catch (ExecutionException e) {
            tmpResult.setReturnCode(Statuses.esException);
            tmpResult.setReturnString(e.toString());
            e.printStackTrace();
        }
        if(response==null || response.status()==null){
            tmpResult.setReturnCode(Statuses.unknownResponse);
            return tmpResult;
        }
        tmpResult.setReturnCode(response.status().getStatus());
        return tmpResult;
    }

    /**
     * 删除一个文档
     * @param indexName 索引名字
     * @param typeName 类型名字
     * @param id 文档id
     * @return
     */
    public ESResult deleteById(String indexName, String typeName, String id) {
        ESResult tmpResult=new ESResult();
        DeleteResponse response = client.prepareDelete(indexName, typeName, id).get();
        if(response==null || response.status()==null){
            tmpResult.setReturnCode(Statuses.unknownResponse);
            return tmpResult;
        }
        tmpResult.setReturnCode(response.status().getStatus());
        return tmpResult;
    }

    /**
     * 每次操作完毕后， 都需要调用关闭方法
     */
    public void close(){
        if(this.client==null){
            return;
        }
        this.client.close();
    }


    public String getClusterName() {
        return clusterName;
    }

    public void setClusterName(String clusterName) {
        this.clusterName = clusterName;
    }

    public Map<String, Integer> getMapTransports() {
        return mapTransports;
    }

    public void setMapTransports(Map<String, Integer> mapTransports) {
        this.mapTransports = mapTransports;
    }
}
